package com.fingersoft.im

//import com.facebook.stetho.Stetho
import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Message
import android.os.StrictMode
import android.text.TextUtils
import android.util.Log
import androidx.multidex.MultiDex
import cn.fingersoft.android.app.ActivityLifecycleEvent
import cn.fingersoft.android.app.ActivityLifecycleMode
import cn.fingersoft.common.commonModule
import cn.fingersoft.common.eventbus.FEventBus
import cn.fingersoft.eben.EBenSignContext
//import cn.fingersoft.emp.service.helper.ComponentHelper
import cn.fingersoft.facebook.react.bridge.runOnUiThread
import cn.fingersoft.im.common.navigation.*
import cn.fingersoft.util.BuildConfigUtil
import com.alibaba.fastjson.JSON
import com.fingersoft.business.BusinessContext
import com.fingersoft.business.BusinessContext.Companion.user
import com.fingersoft.business.BusinessContext.Companion.webView
import com.fingersoft.business.api.IApi
import com.fingersoft.business.device.IDeviceProvider
import com.fingersoft.business.filemanager.FileManagerEvent
import com.fingersoft.business.filemanager.FileManagerProvider
import com.fingersoft.business.login.ILoginProvider
import com.fingersoft.business.main.MainProvider
import com.fingersoft.business.user.IUserBehaviorListener
import com.fingersoft.business.user.IUserProvider
import com.fingersoft.business.user.UserInfo
import com.fingersoft.business.webview.WebViewOpenEvent
import com.fingersoft.color.ColorUtils
import com.fingersoft.common.CommonContext
import com.fingersoft.common.ICallback
import com.fingersoft.common.preference.AppPreferenceHelper
import com.fingersoft.cycle.PluginManager
import com.fingersoft.dcloud.DCloudContext
import com.fingersoft.dexload.DexLoadUtil
import com.fingersoft.dexload.LunchModeHelper
import com.fingersoft.feature.appwidget.SealAppWidgetContext
import com.fingersoft.feature.common.SealCheckApiContext
import com.fingersoft.feature.cordova.SealCordovaContext
import com.fingersoft.feature.deviceverify.SealDeviceVerifyContext
import com.fingersoft.feature.ebensign.SealEbenSignContext
import com.fingersoft.feature.enterpriseconfig.MyEnterpriseConfigProvider
import com.fingersoft.feature.filemanager.FileManagerContext
import com.fingersoft.feature.filemanager.SealFileManagerContext
import com.fingersoft.feature.filemanager.ui.SelectfolderActivity
import com.fingersoft.feature.haikangmonitor.HaikangmonitorContext
import com.fingersoft.feature.haikangmonitor.SealHaikangmonitorCallBack
import com.fingersoft.feature.loading.LoadingContext
import com.fingersoft.feature.loading.SealLoadingContext
import com.fingersoft.feature.lock.SealLockCallBackImpl
import com.fingersoft.feature.login.LoginContext
import com.fingersoft.feature.login.SealLoginContext
import com.fingersoft.feature.login.SealLoginContext2
import com.fingersoft.feature.login.TelAlertDialog
import com.fingersoft.feature.newlock.LockContext
import com.fingersoft.feature.personal.PersonalContext
import com.fingersoft.feature.personal.SealPersonalContext
import com.fingersoft.feature.plugins.SealPluginsContext
import com.fingersoft.feature.push.huawei.MHmsConnectHelper
import com.fingersoft.feature.remotefile.SealRemoteContext
import com.fingersoft.feature.scheme.SchemeConext
import com.fingersoft.feature.scheme.SealSchemeContext
import com.fingersoft.feature.signpad.SealSignPadContext
import com.fingersoft.feature.splash.SealSplashContext
import com.fingersoft.feature.userinfo.api.UserApi
import com.fingersoft.feature.webview.SealWebviewCallBackImpl
import com.fingersoft.feature.webview.WebViewContext
import com.fingersoft.feature.welcome.SealWelcomeContext
import com.fingersoft.feature.welcome.SplashConext
import com.fingersoft.im.api.JSONObjectCallback
import com.fingersoft.im.api.StringArrayResponse2
import com.fingersoft.im.api.UserAgent
import com.fingersoft.im.api.base.BaseModelCallback2
import com.fingersoft.im.api.base.BaseResponse2
import com.fingersoft.im.base.BaseActivityCycleProvider
import com.fingersoft.im.base.MyActivityManager
import com.fingersoft.im.crash.CrashHandler
import com.fingersoft.im.event.EventManager
import com.fingersoft.im.ui.ChooseFileActivity
import com.fingersoft.im.ui.home.MainActivity2
import com.fingersoft.im.ui.home.useUi3
import com.fingersoft.im.utils.*
import com.fingersoft.im.utils.AppUtils.*
import com.fingersoft.plugins.PluginsContext
import com.fingersoft.plugins.pdf.PdfReader
import com.fingersoft.remotefile.RemotefileContext
import com.fingersoft.sso.MySSOProvider
import com.fingersoft.sso.SSO
import com.fingersoft.stomp.MyStompClient
import com.fingersoft.theme.ThemeM
import com.fingersoft.util.AppEventType
import com.fingersoft.util.AppEventUtil
import com.fingersoft.util.RootCheckUtil
import com.google.gson.Gson
import com.lzy.okgo.OkGo
import com.lzy.okgo.callback.AbsCallback
import com.lzy.okgo.callback.StringCallback
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Response
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONException
import org.json.JSONObject
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import java.io.File
import java.lang.ref.WeakReference
import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

@Suppress("unused")
class MyApplication2 : MyApplication(), IUserBehaviorListener, IDeviceProvider, ILoginProvider {

    val TAG = "im.MyApplication2"
    companion object {
        var mHandler: IHandler? = null
        fun getMainHandler(): IHandler? {
            return mHandler
        }
    }

    class IHandler(application: MyApplication2) : Handler() {
        var mApplication = application
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                0 -> {
                    PersonalContext.instance.doLoginOut(mApplication)
                    msg.obj?.let {
                        ToastUtils.show(it.toString())
                    }
                }
                1 -> {
                    val body = msg.obj.toString()
                    try {
                        val js = JSONObject(body)
                        val title = js.getString("title")
                        val content = js.getString("content")
                        val button = js.getString("button")
                        val m = TelAlertDialog(mApplication, title, content, button, true)
                        m.show()
                    } catch (e: JSONException) {
                        e.printStackTrace()
                    }

                }
            }
        }
    }

    private fun isKingGridShowProcess(): Boolean {
        val currentProcessName = this.getCurProcessName()
        Log.i(TAG, "processName=$currentProcessName,kinggrid_show=${this.packageName}:kinggrid_pdfshow")
        return "$packageName:kinggrid_pdfshow" == currentProcessName
    }

    private fun isPreloaddexProcess(): Boolean {
        return "$packageName:preloaddex" == getCurProcessName()
    }

    private fun isWidgetProcess(): Boolean {
        return "$packageName:widget" == getCurProcessName()
    }

    override fun logout() {
        PersonalContext.instance.doLoginOut(this)
    }

    override fun login() {
        PersonalContext.instance.login(this)
    }

    /**
     * @return if success return true,if false need notify user to choice whether continue login.
     * */
    override fun onLogin(context: Context, user: UserInfo): Boolean {
        MyStompClient.createStompClient(mHandler)
        MHmsConnectHelper.doInit(this)
        return true
    }

    /**
     * @return if success return true,if false need notify user to choice whether continue logout.
     * */
    override fun onLogout(context: Context, user: UserInfo): Boolean {
        MyStompClient.disconnect()
        return true
    }

    override fun registerDevice(extra: HashMap<String, String>, callback: ICallback<String>) {
        SealLoginContext.registerDevice(this, extra, callback)
    }

    private fun onCreateing() {
        BusinessContext.init(this, AppConfigUtils(this))
        BusinessContext.api = object : IApi {
            override fun post(path: String, params: JSONObject, callback: AbsCallback<String>) {
                OkGo.post(getApiUrl(path, J_ECODE))
                    .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                    .headers("Connection", "close")
                    .upJson(params.toString())
                    .execute(callback)
            }

            override fun getApiUrl(path: String): String? {
                return getApiUrl(path, J_ECODE)
            }

            override suspend fun jsonPost(path: String, params: JSONObject): JSONObject? = suspendCoroutine { cont ->
                try {
                    // http://redmine.ishangban.com/redmine/issues/6871 url参数可以是全路径也可以为非全路径
                    val url = if (path.startsWith("http://") || path.startsWith("https://")) path else getApiUrl(path, J_ECODE)
                    OkGo.post(url)
                        .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                        .headers("Connection", "close")
                        .upJson(params.toString())
                        .execute(object : JSONObjectCallback() {
                            override fun onSuccess(p0: JSONObject?, p1: Call?, p2: Response?) {
                                cont.resume(p0)
                            }

                            override fun onError(call: Call?, response: Response?, e: Exception?) {
                                //super.onError(call, response, e)
                                cont.resumeWithException(e ?: Exception("未知错误"))
                            }
                        })
                } catch (e: Exception) {
                    cont.resumeWithException(e ?: Exception("未知错误"))
                }
            }

            override fun <T : BaseResponse2<*>?> postJson(path: String, params: Any, baseModelCallback2: BaseModelCallback2<T>) {
                val jsonString = if (params is String) params else JSON.toJSONString(params)
                OkGo.post(getApiUrl(path, J_ECODE))
                    .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                    .headers("Connection", "close")
                    .upJson(jsonString)
                    .execute(baseModelCallback2)
            }

            override fun upload(path: String, tag: Any, params: HashMap<String, String>, filePaths: List<String>, callback: BaseModelCallback2<StringArrayResponse2>) {

                val request = OkGo.post(getApiUrl("i/file/upload", J_ECODE))
                    .tag(tag)
                    .upJson(JSONUtils.toJsonString(params))
                for (filePath in filePaths) {
                    request.params("file", File(filePath))
                }
                request.execute(callback)
            }

            override fun <T : BaseResponse2<*>?> upload(path: String, params: Map<String, String>, files: List<File>, callback: BaseModelCallback2<T>) {
                OkGo.post(getApiUrl(path, J_ECODE))
                    .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                    .params(params)
                    .addFileParams("file", files)
                    .execute(callback)
            }


            override fun <T : BaseResponse2<*>?> post(path: String, params: java.util.HashMap<String, String>, callback2: BaseModelCallback2<T>) {
                OkGo.post(getApiUrl(path, J_ECODE))
                    .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                    .headers("Connection", "close")
                    .upJson(JSONUtils.toJsonString(params))
                    .execute(callback2)
            }

            override operator fun <T> get(path: String, callback: AbsCallback<T>) {
                OkGo.get(getApiUrl(path, J_ECODE))
                    .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                    .execute(callback)
            }
        }
        BusinessContext.user = object : IUserProvider() {
            override fun getApiStampTime(): Long {
                return AppUtils.getUser().apiTimeStamp
            }

            override fun getUserToken(): String? {
                return AppUtils.getTokenInfo().userToken
            }

            override fun getDeviceId(): String? {
                return AppUtils.getTokenInfo().did
            }

            override fun isLogin(): Boolean {
                return AppUtils.isLogged()
            }

            override suspend fun getOnlineType(): String? {
                val id = getId() ?: return null
                val ids = ArrayList<String>()
                ids.add(id)
                val arrayList = UserApi(this@MyApplication2).getOnlineType(ids)
                return arrayList?.find { it?.userId == id }?.onLineType
            }

            override fun SubscribeOnlineStatus(useid: String) {
                val stompClient = MyStompClient.mStompClient ?: return
                stompClient.topic("/user/$useid/user/notice")
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe { topicMessage ->
                        //                    "data": {
                        //                        "type": "onLineType"
                        //                        "body":{
                        //                            "userId": "",  //用户id
                        //                                    "type": "0"  //0:离线, 1:手机端在线, 2:pc端在线, 3:手机+pc在线
                        //                        }
                        //                    }
                        try {
                            val jb = JSONObject(topicMessage.payload)
                            val code = jb.getInt("code")
                            val msg = jb.getString("msg")
                            if (code == 403) {

                            }
                            if (code == 200) {
                                if (!jb.isNull("data")) {
                                    val data = jb.getJSONObject("data")

                                    if (data.has("type")) {
                                        val type = data.getString("type")
                                        if (type == "onLineType") {
                                            val body = data.getJSONObject("body")
                                            EventBus.getDefault().post(EventManager.OnlineStatus(body.getString("userId"), body.getString("type")))
                                        }
                                    }
                                }

                            }
                        } catch (e: JSONException) {
                            e.printStackTrace()
                        }
                    }
            }

            override fun getOnLineType(context: Activity, userIds: String, iCallback: ICallback<*>) {
                val params = HashMap<String, Array<String?>>()
                val ids = arrayOfNulls<String>(1)
                ids[0] = userIds
                params["userIds"] = ids
                val gson = Gson()
                val jsonStr = gson.toJson(params)
                PersonalContext.instance.setPassword(context, "i/user/getOnLineType", jsonStr, iCallback)
            }

            override fun kickedOfflineByOtherClient(context: Context) {
                if (AppPreferenceHelper().getBoolean("isNotKickOut", false)) {

                } else {
                    context.runOnUiThread {
                        ToastUtils.show(R.string.login_rong_kit_off_tips)
                    }
                }
                AppUtils.kickedOfflineByOtherClient(context)
                FEventBus.default.post(EventManager.OnRNkickedOfflineByOtherClient())
            }

            override fun getUserInfo(): UserInfo? {
                val user = AppUtils.getUser()
                if (TextUtils.isEmpty(user.userId)) return null
                val userInfo = UserInfoManager.getCurrentUserInfo()
                return UserInfo(user.userId!!, user.imid, user.realName, user.empLivingPhoto, user.userName, userInfo.phone, userInfo.mobile, userInfo.deptId)
            }

            override fun getId(): String? {
                return AppUtils.getUser().userId
            }

            override fun getImid(): String? {
                return AppUtils.getUser().imid
            }

            override suspend fun validateUser(): Boolean = suspendCoroutine {
                try {
                    OkGo.post(getApiUrl("i/user/userInfo", J_ECODE))
                        .headers("Emp-Info", JSONUtils.toJsonString(UserAgent(AppUtils.getTokenInfo().userToken, AppUtils.getTokenInfo().did)))
                        .upJson("")
                        .execute(object : StringCallback() {
                            override fun onSuccess(p0: String?, p1: Call?, p2: Response?) {
                                it.resume(p2?.isSuccessful == true)
                            }

                            override fun onError(call: Call?, response: Response?, e: java.lang.Exception?) {
                                it.resume(false)
                            }
                        })
                } catch (e: Exception) {
                    it.resume(false)
                }
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        Log.i(TAG, "MyApplication2.onCreate()")
        if (isPreloaddexProcess()) {
            BuildConfigUtil.init(this, BuildConfig::class.java)
            AppEventUtil.initRootFilePath(cacheDir.path)
            CrashHandler.getInstance().init(this, BuildConfigUtil.getBoolean("crashLogToServer"))
            return
        }

        startKoin {
            androidLogger()
            androidContext(this@MyApplication2)
            modules(commonModule)
        }
        //所有进程都需要的初始化
        BuildConfigUtil.init(this, BuildConfig::class.java)

        if (BuildConfigUtil.getBoolean("useRootCheck") && RootCheckUtil().isRoot) {
            killProcess()
            return
        }

        AppEventUtil.initRootFilePath(cacheDir.path)
        CrashHandler.getInstance().init(this, BuildConfigUtil.getBoolean("crashLogToServer"))

        // 区分进程的 初始化
        if (isWidgetProcess()) {
            return
        }

        closeAndroidPDialog()
//        ComponentHelper.getInstance().init(this, BuildConfig.DEBUG)
        CommonContext.init(this, DEBUG, isScreenShotForbidden(), SealCheckApiContext(this))
        FEventBus.init(this)
        if (isMainProcess()) {
            FEventBus.default.register(this)
        }
        AppUtils.init(this, BuildConfig::class.java)
        BusinessContext.enterpriseConfigProvider = MyEnterpriseConfigProvider()

        val processName = getCurProcessName()
        if (processName == packageName || processName == "$packageName:pushservice") {
            DCloudContext.init(this)
            if (processName == "$packageName:pushservice") {
                return
            }
        }
        DCloudContext.init(this)
        if (isKingGridShowProcess()) {
            FEventBus.default.post(ActivityLifecycleEvent(ActivityLifecycleMode.CREATE, MyApplication2::class.java.name))
            Log.i("MyApplication", "IAppPdfPlugin,签批进程，签批插件初始化")
            PluginsContext.init(SealPluginsContext(this))
            PluginManager.onApplicationCreate(this)
            WebViewContext.init(SealWebviewCallBackImpl())
            PluginManager.onApplicationCreated(this)
            onCreateing()
            AppConfigUtils.getAppConfigSync(this)
            return
        }
        BusinessContext.main = object : MainProvider() {
            override fun startConversation(context: Context) {
                val intent = Intent(context, MainActivity2::class.java)
                intent.putExtra("uifrom", 0)
                intent.putExtra("selected", "conversation")
                context.startActivity(intent)
            }

            override fun startSystemConversation(activity: Activity) {
                val intent = Intent(activity, MainActivity2::class.java)
                intent.putExtra("systemconversation", true)
                activity.startActivity(intent)
            }
        }
        BusinessContext.fileManager = object : FileManagerProvider() {
            override fun readPdfFromUrl(context: Context, previewUrl: String?) {
                PdfReader.getInstance().readPdfFromUrl(context, previewUrl, PdfReader.ORIENATION_VER, false)
            }

            /**
             * @param conversationType Conversation.ConversationType
             * */
            override fun startChooseFileActivityForResult(context: Activity, targerid: String, conversationType: Any) {
                ChooseFileActivity.startActivityForResult(context, targerid, conversationType)
            }

            override fun startSelectFolderActivity(context: Context, folderId: String?, name: String, file: Uri, isfromIM: Boolean) {
                SelectfolderActivity.startSelectfolderActivity(context, folderId, name, file, isfromIM)
            }

            override fun openFileByWebView(context: Context, path: String, name: String, uid: String) {
                PluginsContext.instance.startMyFile(context, path, name, uid)
            }

            override fun filedown_create_log(context: Activity, messageId: String, groupId: String, fileName: String, fileSize: String, fromImid: String, iCallback: ICallback<*>) {
                val params = HashMap<String, String>()
                params["messageId"] = messageId
                params["groupId"] = groupId
                params["fileName"] = fileName
                params["fileSize"] = fileSize
                params["fromImid"] = fromImid
                val gson = Gson()
                val jsonStr = gson.toJson(params)

                PersonalContext.instance.setPassword(context, "i/im/filedown/createLog", jsonStr, iCallback)
            }

            override fun savePreviewFileInfo(uid: String, path: String, name: String?, size: Long?, type: String?) {
                SealFileManagerContext.savePreviewFileInfo(uid, path, name, size, type)
            }

            override fun saveDownLoadFileInfo(path: String?, name: String?, size: Long?, type: String?, time: Long) {
                SealFileManagerContext.saveDownLoadFileInfo(path, name, size, type, time)
            }

            override fun deleteMyFile(path: String?) {
                SealFileManagerContext.deleteMyFile(path)
            }

            override fun filedown_query_all(context: Activity, messageId: String, groupId: String, iCallback: ICallback<*>) {
                val params = HashMap<String, String>()
                params["messageId"] = messageId
                params["groupId"] = groupId
                val gson = Gson()
                val jsonStr = gson.toJson(params)

                PersonalContext.instance.setPassword(context, "i/im/filedown/queryAll", jsonStr, iCallback)
            }
        }
        PluginsContext.init(SealPluginsContext(this))
        PluginManager.onApplicationCreate(this)
        onCreateing()
        preferences = getSharedPreferences("demo", 0)
        appInitBeforeConfig()

        BusinessContext.userBehaviorListeners.add(this)
        BusinessContext.device = this
        BusinessContext.login = this
        PluginManager.onApplicationCreated(this)
        mHandler = IHandler(this)
        if (useLogin()) {
            LoginContext.init(SealLoginContext2(this))
        }

        if (applicationInfo.packageName == ApplicationUtils.getCurProcessName(this)) {
            Log.i(TAG, "use VPN is:${useVPN()};setVPN_ConnectMode is ${BuildConfigUtil.getString("setVPN_ConnectMode", "")}")
            if (useVPN() && BuildConfigUtil.getString("setVPN_ConnectMode", "").contains("always")) {
                registVPNBroadcastReceiver(this)
                BusinessContext.mVPNProvider?.init(getVPNAddress(), getVPNUsername(), getVPNPassword(), getVPNNtlsAddress())
                return
            } else {
                onICreate()
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(event: WebViewOpenEvent) {
        webView?.openWebView(this, event.url, event.title)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(event: FileManagerEvent.OpenPreviewEvent) {
        BusinessContext.fileManager.preview(MyActivityManager.getInstance().currentActivity ?: this, event.url)
    }



    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(event: ActivityLifecycleEvent) {
        Log.i(TAG, "onEvent:ActivityLifecycleEvent:mode=${event.mode}")
        if (event.activityName == MyApplication2::class.java.name) {
            mFinalCountKinggrid = 0
            return
        }
        @Suppress("NON_EXHAUSTIVE_WHEN")
        when (event.mode) {
            ActivityLifecycleMode.START -> {
                mFinalCountKinggrid++
                checkApp2Foreground(event.activityName)
            }
            ActivityLifecycleMode.RESUME -> {
                checkLock2foreground(event.activityName)
            }
            ActivityLifecycleMode.STOP -> {
                mFinalCountKinggrid--
                checkLock2background(event.activityName)
                checkApp2Background()
            }
        }
    }
    override fun onTerminate() {
        PluginManager.onApplicationTerminating(this)
        super.onTerminate()
        PluginManager.onApplicationTerminate(this)

        AppEventUtil.writeLandingState(AppEventType.AppKilled)
    }

    override fun attachBaseContext(base: Context) {
        Log.i(TAG,"attachBaseContext()")
        super.attachBaseContext(base)
        if (isWidgetProcess()) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                GlobalScope.launch(Dispatchers.IO) {
                    DexLoadUtil().setPreloadstatus(WeakReference(this@MyApplication2), false)
                    MultiDex.install(this@MyApplication2)
                    DexLoadUtil().setPreloadstatus(WeakReference(this@MyApplication2), true)
                }
                return
            } else {
                DexLoadUtil().setPreloadstatus(WeakReference(this@MyApplication2), true)
                return
            }
            return
        }

        if (isMainProcess()) {
            LunchModeHelper.getInstance().markOpenApp(this, false)
            DexLoadUtil().setIsAppRestartOnce(WeakReference(this), true)
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            if (!isPreloaddexProcess()) {
                if (needWait()) {
                    /**
                    第一次启动APP由于MultiDex将会非常缓慢，某些低端机可能ANR。
                    因此这里的做法是挂起主进程，开启:async_launch进程执行dexopt。
                    dexopt执行完毕，主进程重新变为前台进程，继续执行初始化。
                    主进程在这过程中变成后台进程，因此阻塞将不会引起ANR。
                     */
                    val thread = DexInstallDeamonThread(base)
                    thread.start()

                    //阻塞等待:async_launch完成加载
                    synchronized(lock) {
                        try {
                            lockWait()
                        } catch (e: InterruptedException) {
                            e.printStackTrace()
                        }

                    }
                    thread.exit()
                    MultiDex.install(this)
                    Log.d("Jooper", "dexopt finished. alloc MultiDex.install()")
                } else {
                    MultiDex.install(this)
                }
            }
        } else {
            MultiDex.install(this)
        }

        PluginManager.init(this, PLUGIN_NAMES)
        PluginManager.attachBaseContext(this)

    }

    @SuppressWarnings("deprecation")
    fun needWait(): Boolean {
        return LunchModeHelper.getInstance().isFirstOpen
    }

    private var dexInstalled: Boolean = false
    private var dexInstallationChecked: Boolean = false
    protected var mFinalCountKinggrid: Int = 0//金格进程Activity计数

    private fun isMainProcess(): Boolean {
        val am: ActivityManager = this.getSystemService(ACTIVITY_SERVICE) as ActivityManager
        val pid = android.os.Process.myPid()
        return am.runningAppProcesses.any { it.pid == pid && packageName == it.processName }
    }

    override fun showToastWhenApp2Background() {
        val toast = BuildConfigUtil.getString("toastWhenApp2Background", "")
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            if (!TextUtils.isEmpty(toast)
                && !DexLoadUtil().getIsAppRestartOnce(WeakReference(this))
                && !isTopProcessBelongs2App(BuildConfig.APPLICATION_ID)) {
                mHandler?.postDelayed({
                    ToastUtils.showWithoutDelay(toast)
                }, 1000)
            } else {
                DexLoadUtil().setIsAppRestartOnce(WeakReference(this), false)
            }
        } else {
            if (!TextUtils.isEmpty(toast)) {
                ToastUtils.showWithoutDelay(toast)
            }
        }
    }

    /* fix Detected problems with API compatibility(visit g.co/dev/appcompat for more info */
    private fun closeAndroidPDialog() {
        if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            try {
                val aClass = Class.forName("android.content.pm.PackageParser\$Package")
                val declaredConstructor = aClass.getDeclaredConstructor(String::class.java)
                declaredConstructor.isAccessible = true
            } catch (e: Exception) {
                e.printStackTrace()
            }

            try {
                val cls = Class.forName("android.app.ActivityThread")
                val declaredMethod = cls.getDeclaredMethod("currentActivityThread")
                declaredMethod.isAccessible = true
                val activityThread = declaredMethod.invoke(null)
                val mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown")
                mHiddenApiWarningShown.isAccessible = true
                mHiddenApiWarningShown.setBoolean(activityThread, true)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun existProcess(name: String): Boolean {
        val am = (getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
        val processInfos = am.getRunningAppProcesses()
        for (info in processInfos) {
            if (name == info.processName) {
                return true
            }
        }
        return false
    }

    override fun getFinalCount(): Int {
        if (existProcess("$packageName:kinggrid_pdfshow")) {
            return mFinalCount + mFinalCountKinggrid
        }
        return mFinalCount
    }

    override fun onLowMemory() {
        // 低内存的时候执行
        super.onLowMemory()
        AppEventUtil.writeLandingState(AppEventType.AppMemoryWarning)
    }

    override fun onTrimMemory(level: Int) {
        // 程序在内存清理的时候执行
        super.onTrimMemory(level)
    }

    override fun reConnectSocket() {
        if (user?.isLogin() == true) {
            MyStompClient.disconnect()
            MyStompClient.createStompClient(mHandler)
        }
    }

    /**
     *  调整初始化先后顺序或者位置时需要注意,有可能造成运行错误,会产生闪退日志
     *  */
    override fun appInitBeforeConfig() {
        Log.println(Log.INFO, "application", "application oncreate..............")
        SealSignPadContext.init(this)
        WebViewContext.init(SealWebviewCallBackImpl())


        SealCordovaContext.init(this)


        if (useMdm() && isMDMEnable()) {
        }
        try {
            SSO.init(object : MySSOProvider() {

            })
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e("MyApplication", e.message, e)
        }

        if (applicationInfo.packageName != ApplicationUtils.getCurProcessName(applicationContext))
            return


        initOkGo()


        LogUtils.init(DEBUG)

        if (useWelcome()) {
            BusinessContext.welcome?.init(SealWelcomeContext())
        }
        SplashConext.init(SealSplashContext(this))
        LoadingContext.init(SealLoadingContext())
        if (useLock()) {
            LockContext.init(this, SealLockCallBackImpl(this))
        }

        if (useScheme()) {
            SchemeConext.init(SealSchemeContext())
        }

        if (useMdm()) {
            try {
                //                MDMService.getInstance().init(getAppContext(), DeviceHelper.getDeviceID(getAppContext()));
            } catch (e: Exception) {
                e.printStackTrace()
            }

        }
        // if (useFileManager()) {
        FileManagerContext.init(SealFileManagerContext())
        // }

        if (useTheme()) {
            val list = mutableListOf<String>()
            list.addAll(ColorUtils.getStringArray(this, R.array.theme_color))
            if (useUi3()) {
                list.addAll(ColorUtils.getStringArray(this, R.array.theme_ui3_color))
            }
            ThemeM.saveThemeColor(list.toTypedArray())
        }

        if (useHaikangMonitor()) {
            HaikangmonitorContext.init(SealHaikangmonitorCallBack())
        }

        BaseActivityCycleProvider.init(cycles)
        addActivityLifeCallbackListener()
        PluginManager.appInitBeforeConfig(this)
        if (useSetting()) {
            PersonalContext.init(SealPersonalContext(this))
        }

        RemotefileContext.init(SealRemoteContext(this))

        if (EBenHandwritingEnabled()) {
            EBenSignContext.init(SealEbenSignContext())
        }

        if (useLogin()) {
            LoginContext.init(SealLoginContext2(this))
        }

        if (useAppWidget()) {
            BusinessContext.appWidget?.init(SealAppWidgetContext())
        }

        if (useDeviceVerify()) {
            BusinessContext.deviceVerify?.init(SealDeviceVerifyContext())
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val builder = StrictMode.VmPolicy.Builder()
            StrictMode.setVmPolicy(builder.build())
        }
    }
}
